package fun

import (
	"encoding/json"
	"errors"
	"reflect"
	"strconv"
)

// @title: Interface转换string
// @param: val(interface)
// @return: string
// @description:
// @date: 2022/7/3 21:40
func InterfaceToStr(val interface{}) (string, error) {
	var str string

	if val == nil {
		return "", errors.New("Conversion failed `val` is nil")
	}

	switch value := val.(type) {
	case float64:
		str = strconv.FormatFloat(value, 'f', -1, 64)
		return str, nil
	case float32:
		str = strconv.FormatFloat(float64(value), 'f', -1, 64)
		return str, nil
	case int:
		str = strconv.Itoa(value)
		return str, nil
	case uint:
		str = strconv.Itoa(int(value))
		return str, nil
	case int8:
		str = strconv.Itoa(int(value))
		return str, nil
	case uint8:
		str = strconv.Itoa(int(value))
		return str, nil
	case int16:
		str = strconv.Itoa(int(value))
		return str, nil
	case uint16:
		str = strconv.Itoa(int(value))
		return str, nil
	case int32:
		str = strconv.Itoa(int(value))
		return str, nil
	case uint32:
		str = strconv.Itoa(int(value))
		return str, nil
	case int64:
		str = strconv.FormatInt(value, 10)
		return str, nil
	case uint64:
		str = strconv.FormatUint(value, 10)
		return str, nil
	case string:
		str = val.(string)
		if IsScientificNotation(str) {
			amount, err := ScientificNotationToStrings(str, 15)
			if err != nil {
				return "", err
			}
			amount = RemoveAllZerosFromLastDecimal(amount)
			return amount, nil
		}
		return str, nil
	case []byte:
		str = string(val.([]byte))
		return str, nil
	case bool:
		if value {
			return "true", nil
		}
		return "false", nil
	case json.Number:
		return value.String(), nil
	//----------------------------
	case *float64:
		str = strconv.FormatFloat(*value, 'f', -1, 64)
		return str, nil
	case *float32:
		f := *value
		str = strconv.FormatFloat(float64(f), 'f', -1, 64)
		return str, nil
	case *int:
		str = strconv.Itoa(*value)
		return str, nil
	case *uint:
		str = strconv.Itoa(int(*value))
		return str, nil
	case *int8:
		str = strconv.Itoa(int(*value))
		return str, nil
	case *uint8:
		str = strconv.Itoa(int(*value))
		return str, nil
	case *int16:
		str = strconv.Itoa(int(*value))
		return str, nil
	case *uint16:
		str = strconv.Itoa(int(*value))
		return str, nil
	case *int32:
		str = strconv.Itoa(int(*value))
		return str, nil
	case *uint32:
		str = strconv.Itoa(int(*value))
		return str, nil
	case *int64:
		str = strconv.FormatInt(*value, 10)
		return str, nil
	case *uint64:
		str = strconv.FormatUint(*value, 10)
		return str, nil
	case *string:
		str = *value
		return str, nil
	case *[]byte:
		str = string(*value)
		return str, nil
	case *bool:
		if *value {
			return "true", nil
		}
		return "false", nil
	case *json.Number:
		return value.String(), nil
	default:
		newValue, _ := json.Marshal(val)
		str = string(newValue)
		return str, nil
	}
}

// @title: Interface转换float64
// @param: val(interface)
// @return: float64, error
// @description:
// @date: 2022/7/3 21:40
func InterfaceToFloat64(val interface{}) (float64, error) {
	if val == nil {
		return 0, errors.New("Conversion failed `val` is nil")
	}

	switch value := val.(type) {
	case float64:
		return value, nil
	case float32:
		return float64(value), nil
	case uint8:
		return float64(value), nil
	case uint16:
		return float64(value), nil
	case uint32:
		return float64(value), nil
	case uint64:
		return float64(value), nil
	case uint:
		return float64(value), nil
	case int8:
		return float64(value), nil
	case int16:
		return float64(value), nil
	case int32:
		return float64(value), nil
	case int64:
		return float64(value), nil
	case int:
		return float64(value), nil
	case bool:
		if value {
			return 1, nil
		}
		return 0, nil
	case []byte:
		str := string(val.([]byte))
		return strconv.ParseFloat(str, 64)
	case string:
		return strconv.ParseFloat(value, 64)
	case json.Number:
		return value.Float64()
	//---------------------------------------------
	case *float64:
		return *value, nil
	case *float32:
		return float64(*value), nil
	case *uint8:
		return float64(*value), nil
	case *uint16:
		return float64(*value), nil
	case *uint32:
		return float64(*value), nil
	case *uint64:
		return float64(*value), nil
	case *uint:
		return float64(*value), nil
	case *int8:
		return float64(*value), nil
	case *int16:
		return float64(*value), nil
	case *int32:
		return float64(*value), nil
	case *int64:
		return float64(*value), nil
	case *int:
		return float64(*value), nil
	case *bool:
		if *value {
			return 1, nil
		}
		return 0, nil
	case *[]byte:
		var b []byte
		b = *val.(*[]byte) // 解引用指针得到 []byte
		str := string(b)   // 将 []byte 转换为 string
		return strconv.ParseFloat(str, 64)
	case *string:
		return strconv.ParseFloat(*value, 64)
	case *json.Number:
		return value.Float64()
	default:
		return 0, errors.New("Conversion failed `val` unknown type")
	}
}

// @title: Interface转int64
// @param: val(interface)
// @return: int64, error
// @description:
// @date: 2022/7/3 21:40
func InterfaceToInt64(val interface{}) (int64, error) {
	switch value := val.(type) {
	case float64:
		return Float64ToInt64(value), nil
	case float32:
		return Float32ToInt64(value), nil
	case uint8:
		return int64(value), nil
	case uint16:
		return int64(value), nil
	case uint32:
		return int64(value), nil
	case uint64:
		return int64(value), nil
	case uint:
		return int64(value), nil
	case int8:
		return int64(value), nil
	case int16:
		return int64(value), nil
	case int32:
		return int64(value), nil
	case int64:
		return value, nil
	case int:
		return int64(value), nil
	case bool:
		if value {
			return 1, nil
		}
		return 0, nil
	case json.Number:
		return value.Int64()
	case string:
		v, err := StrToInt64(value)
		if err != nil {
			return 0, err
		}
		return v, nil
	case []byte:
		str := string(value)
		v, err := StrToInt64(str)
		if err != nil {
			return 0, err
		}
		return v, nil
	//------------------------------------
	case *float64:
		return Float64ToInt64(*value), nil
	case *float32:
		return Float32ToInt64(*value), nil
	case *uint8:
		return int64(*value), nil
	case *uint16:
		return int64(*value), nil
	case *uint32:
		return int64(*value), nil
	case *uint64:
		return int64(*value), nil
	case *uint:
		return int64(*value), nil
	case *int8:
		return int64(*value), nil
	case *int16:
		return int64(*value), nil
	case *int32:
		return int64(*value), nil
	case *int64:
		return *value, nil
	case *int:
		return int64(*value), nil
	case *bool:
		if *value {
			return 1, nil
		}
		return 0, nil
	case *json.Number:
		return value.Int64()
	case *string:
		v, err := StrToInt64(*value)
		if err != nil {
			return 0, err
		}
		return v, nil
	case *[]byte:
		str := string(*value)
		v, err := StrToInt64(str)
		if err != nil {
			return 0, err
		}
		return v, nil
	default:
		return 0, errors.New("Conversion failed `val` unknown type")
	}
}

// @title: Interface是否是结构体
// @param: interface
// @return: bool
// @description:
// @date: 2024/7/7 16:45
func InterfaceIsStruct(val interface{}) bool {
	value := reflect.ValueOf(val)
	if value.Kind() == reflect.Ptr {
		// 如果conf是一个指针，我们检查其指向的值
		value = value.Elem()
	}
	return value.Kind() == reflect.Struct
}

// @title: Interface是否是指针
// @param: interface
// @return: bool
// @description:
// @date: 2024/7/7 16:45
func InterfaceIsPtr(val interface{}) bool {
	value := reflect.ValueOf(val)
	if value.Kind() == reflect.Ptr {
		return true
	}
	return false
}
